<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>JavaScript内存分配(JavaScript Memory Allocation)</title>
  <!-- 
  JavaScript 的内存管理是自动化的，通过垃圾回收机制来管理内存的分配和释放。
  1. 内存分配
  - 基本概念：内存分配是指为数据分配内存空间的过程。在 JavaScript 中，内存分配主要分为两种类型：栈内存和堆内存。

  - 栈内存：
    - 用于存储基本数据类型（如： `number` 、 `string` 、 `boolean` 、 `null` 、 `undefined` ）。
    - 存储固定大小的数据，分配和释放速度较快。
    - 采用后进先出（LIFO）的方式管理内存。

  - 堆内存：
    - 用于存储对象和数组等复杂数据类型。
    - 内存大小不固定，分配和释放速度相对较慢。
    - 通过引用来访问堆中的数据。

  2. 垃圾回收
  - 概念：垃圾回收是自动管理内存的机制，负责回收不再使用的内存空间，以避免内存泄漏。

  - 标记-清除算法：
    - 垃圾回收器会定期检查内存中的对象，并标记可达的对象。
    - 未被标记的对象会被认为是垃圾，随后被清除。

  - 引用计数：
    - 通过维护每个对象的引用计数来判断对象是否仍在使用。
    - 当引用计数为零时，该对象会被回收。

  3. 内存泄漏
  - 概念：内存泄漏是指不再使用的内存未被回收，导致可用内存逐渐减少。

  - 常见原因：
    - 全局变量：未清理的全局变量可能导致内存泄漏。
    - 闭包：闭包可能会意外地保持对外部变量的引用。
    - 事件监听器：未移除的事件监听器可能导致对象无法被回收。

  - 预防措施：
    - 避免使用全局变量，使用局部变量和模块化设计。
    - 在不需要时，及时移除事件监听器。
    - 使用弱引用（WeakMap、WeakSet）来避免意外的引用。

  4. 性能优化
  - 内存管理：合理的内存管理可以提高应用程序的性能。
  - 避免频繁的内存分配：通过对象池等技术重用对象，减少内存分配和垃圾回收的频率。
  - 使用轻量级数据结构：尽量使用简单的数据结构来减少内存占用。

  5. 内存泄漏检测工具
    Chrome DevTools
    Firefox Developer Tools
    Safari Web Inspector
    内存泄漏检测工具可以帮助开发者识别和解决内存泄漏问题，从而提高应用程序的性能和稳定性。

  6. 内存泄漏的常见原因
    闭包
    循环引用
    全局变量
    DOM 元素引用
    定时器
    事件监听器

  7. 内存泄漏的解决方案
    避免使用闭包
    使用 WeakMap 和 WeakSet
    清理全局变量
    移除 DOM 元素引用
    清理定时器和事件监听器

  8. 内存泄漏的预防
    使用 WeakMap 和 WeakSet
    避免循环引用

  总结
  JavaScript 的内存分配和管理是一个复杂的过程，涉及栈和堆的内存分配、垃圾回收机制以及内存泄漏的问题。了解这些基本概念和技术可以帮助开发者编写更高效、更稳定的代码，从而优化应用程序的性能。
   -->
</head>
<body>

  <script>
    
    // 1. 栈内存分配和堆内存分配示例
    let num = 10; // 栈内存分配
    let obj = { name: 'John' }; // 堆内存分配

    // 2. 垃圾回收示例
    obj = null; // 将对象引用置为 null，使其成为垃圾

    // 3. 内存泄漏示例
    let leakedObj = { name: 'Leaked' };

    // 3.1 未移除事件监听器
    document.addEventListener('click', function() {
      console.log("3.1 未移除事件监听器", leakedObj);
    });

    // 3.2 预防内存泄漏
    document.removeEventListener('click', function() {
      console.log("3.2 预防内存泄漏", leakedObj);
    });

    // 4. 性能优化示例
    let objPool = []; // 对象池

    function getObject() {
      if (objPool.length === 0) {
        return { name: 'New Object' };
      } else {
        return objPool.pop();
      }
    }

    function releaseObject(obj) {
      objPool.push(obj);
    }

    let newObj = getObject();
    releaseObject(newObj);
    console.log("4. 性能优化示例", objPool);
    
    // 4.1 使用 WeakMap 和 WeakSet - 可以避免内存泄漏，因为它们不会阻止垃圾回收器回收对象
    let weakMap = new WeakMap();
    let weakSet = new WeakSet();

    let obj1 = { name: 'Object 1' };
    let obj2 = { name: 'Object 2' };

    weakMap.set(obj1, 'Value 1');
    weakSet.add(obj2);

    console.log("WeakMap", weakMap.get(obj1)); // 输出: Value 1
    console.log("WeakSet", weakSet.has(obj2)); // 输出: true

    obj1 = null;
    obj2 = null;

  </script>
  
</body>
</html>